package model

import (
	"fmt"
	"regexp"
	"strings"

	"file_explorer/common/util"

	"github.com/spf13/cast"
	"gopkg.in/yaml.v3"
)

const (
	RenameRuleAdd     = "add"      // 指定位置添加内容
	RenameRuleDelete  = "delete"   // 指定位置删除内容
	RenameRuleReplace = "replace"  // 指定内容替换
	RenameRuleExtName = "ext_name" // 修改扩展名
	RenameRuleSeq     = "seq"      // 序列化
)

type RenameRule interface {
	GetDescription() string
	BatchExecute([]*ModifiedFileInfo)
}

func BuildRule(raw map[string]interface{}) RenameRule {
	var rule RenameRule

	switch cast.ToStringMapString(raw["default_rule"])["type"] {
	case RenameRuleAdd:
		rule = &AddRule{}
	case RenameRuleDelete:
		rule = &DeleteRule{}
	case RenameRuleReplace:
		rule = &ReplaceRule{}
	case RenameRuleExtName:
		rule = &ExtNameRule{}
	case RenameRuleSeq:
		rule = &SeqRule{}
	default:
		return nil
	}

	bytes, err := yaml.Marshal(raw)
	if err != nil {
		return nil
	}

	err = yaml.Unmarshal(bytes, rule)
	if err != nil {
		return nil
	}

	return rule
}

type DefaultRule struct {
	Type string `yaml:"type"`
}

// ********** 添加内容规则 ************/

type AddRule struct {
	DefaultRule `yaml:"default_rule"`
	Offset      int    `yaml:"offset"`
	Content     string `yaml:"content"`
}

func (rule *AddRule) GetDescription() string {
	return fmt.Sprintf("第 %d 位插入内容 %s", rule.Offset, rule.Content)
}

func (rule *AddRule) execute(mFileInfo *ModifiedFileInfo) {
	name, extName := mFileInfo.New.SplitFilename()
	newName := ""
	if rule.Offset >= len(name) {
		newName = name + rule.Content
	} else {
		newName = name[:rule.Offset] + rule.Content + name[rule.Offset:]
	}
	mFileInfo.New.Name = util.JoinFilename(newName, extName)
}

func (rule *AddRule) BatchExecute(mFileInfos []*ModifiedFileInfo) {
	for _, mFileInfo := range mFileInfos {
		rule.execute(mFileInfo)
	}
}

func NewAddRule(offset int, content string) *AddRule {
	return &AddRule{
		DefaultRule: DefaultRule{
			Type: RenameRuleAdd,
		},
		Offset:  offset,
		Content: content,
	}
}

// ********** 删除内容规则 ************/

type DeleteRule struct {
	DefaultRule `yaml:"default_rule"`
	Offset      int `yaml:"offset"`
	Length      int `yaml:"length"`
}

func (rule *DeleteRule) GetDescription() string {
	return fmt.Sprintf("第 %d 位开始删除 %d 位", rule.Offset, rule.Length)
}

func (rule *DeleteRule) execute(mFileInfo *ModifiedFileInfo) {
	name, extName := mFileInfo.New.SplitFilename()
	if rule.Offset >= len(name) {
		return
	}
	newName := name[:rule.Offset]
	if rule.Offset+rule.Length < len(name) {
		newName += name[rule.Offset+rule.Length:]
	}

	mFileInfo.New.Name = util.JoinFilename(newName, extName)
}

func (rule *DeleteRule) BatchExecute(mFileInfos []*ModifiedFileInfo) {
	for _, mFileInfo := range mFileInfos {
		rule.execute(mFileInfo)
	}
}

func NewDeleteRule(offset, length int) *DeleteRule {
	return &DeleteRule{
		DefaultRule: DefaultRule{
			Type: RenameRuleDelete,
		},
		Offset: offset,
		Length: length,
	}
}

// ********** 替换规则 ************/

type ReplaceRule struct {
	DefaultRule `yaml:"default_rule"`
	Src         string `yaml:"src"`
	Dst         string `yaml:"dst"`
}

func (rule *ReplaceRule) GetDescription() string {
	return fmt.Sprintf("将 %s 替换为 %s", rule.Src, rule.Dst)
}

func (rule *ReplaceRule) execute(mFileInfo *ModifiedFileInfo) {
	name, extName := mFileInfo.New.SplitFilename()
	reg, _ := regexp.Compile(rule.Src)
	newName := reg.ReplaceAllString(name, rule.Dst)
	mFileInfo.New.Name = util.JoinFilename(newName, extName)
}

func (rule *ReplaceRule) BatchExecute(mFileInfos []*ModifiedFileInfo) {
	for _, mFileInfo := range mFileInfos {
		rule.execute(mFileInfo)
	}
}

func NewReplaceRule(src, dst string) *ReplaceRule {
	return &ReplaceRule{
		DefaultRule: DefaultRule{
			Type: RenameRuleReplace,
		},
		Src: src,
		Dst: dst,
	}
}

// ********** 扩展名规则 ************/

type ExtNameRule struct {
	DefaultRule `yaml:"default_rule"`
	ExtName     string `yaml:"ext_name"`
}

func (rule *ExtNameRule) GetDescription() string {
	return fmt.Sprintf("文件扩展名改为 %s", rule.ExtName)
}

func (rule *ExtNameRule) execute(mFileInfo *ModifiedFileInfo) {
	if mFileInfo.New.IsDir() {
		return
	}
	name, _ := mFileInfo.New.SplitFilename()
	mFileInfo.New.Name = util.JoinFilename(name, rule.ExtName)
}

func (rule *ExtNameRule) BatchExecute(mFileInfos []*ModifiedFileInfo) {
	for _, mFileInfo := range mFileInfos {
		rule.execute(mFileInfo)
	}
}

func NewExtNameRule(extName string) *ExtNameRule {
	return &ExtNameRule{
		DefaultRule: DefaultRule{
			Type: RenameRuleExtName,
		},
		ExtName: extName,
	}
}

// ********** 序列化规则 ************/

type SeqRule struct {
	DefaultRule `yaml:"default_rule"`
	Start       int    `yaml:"start"`
	Width       int    `yaml:"width"`
	Pattern     string `yaml:"pattern"`
}

func (rule *SeqRule) GetNameBySeq(seq int, extName string) string {
	seqFormat := fmt.Sprintf("%%0%dd", rule.Width)
	nameFormat := strings.ReplaceAll(rule.Pattern, "#", seqFormat)
	return util.JoinFilename(fmt.Sprintf(nameFormat, seq), extName)
}

func (rule *SeqRule) GetDescription() string {
	return fmt.Sprintf("序列化，起始序号: %d, 宽度: %d, 模式: %s", rule.Start, rule.Width, rule.Pattern)
}

func (rule *SeqRule) BatchExecute(mFileInfos []*ModifiedFileInfo) {
	for i, mFileInfo := range mFileInfos {
		_, extName := util.SplitFilename(mFileInfo.New.Name)
		mFileInfo.New.Name = rule.GetNameBySeq(i+rule.Start, extName)
	}
}

func NewSeqRule(start, width int, pattern string) *SeqRule {
	if len(pattern) == 0 {
		pattern = "#"
	}

	return &SeqRule{
		DefaultRule: DefaultRule{
			Type: RenameRuleSeq,
		},
		Start:   start,
		Width:   width,
		Pattern: pattern,
	}
}

type RawRenameRuleConf struct {
	Key   string                   `yaml:"key"`
	Rules []map[string]interface{} `yaml:"rules"`
}

type RenameRuleConf struct {
	Key   string       `yaml:"key"`
	Rules []RenameRule `yaml:"rules"`
}

func RenameRuleConfs2Interfaces(items []*RenameRuleConf) []interface{} {
	interfaces := make([]interface{}, 0, len(items))
	for _, item := range items {
		interfaces = append(interfaces, item)
	}
	return interfaces
}
